<?php


namespace app\api\model;
use common;
use hiredis;
use think\Db;
use think\facade\Log;
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */


const AGG_LNG = 0.0002;
const AGG_LAT = 0.0002;

function cord_gen_field($cord)
{
    $lng = round($cord[0] / AGG_LNG) * AGG_LNG;
    $lav = round($cord[1] / AGG_LAT) * AGG_LAT;
    return $lng . '|' . $lav;
}

function get_heat_tag($datetime)
{
    $h = 0;
    $arr = explode(' ', $datetime);
    if (count($arr) > 1) {
        $h = intval($arr[1]);
    }

    $hours = [
        [21, 29],
        [6, 10],
        [11, 15],
        [16, 20],
    ];

    if ($h <= 5) {
        $h += 24;
    }

    for ($i = 0; $i < count($hours); $i++) {
        if ($h >= $hours[$i][0] && $h <= $hours[$i][1]) {
            return $i;
        }
    }
    return -1;
}


function get_heat_tag_and_idletime($datetime, $idletime)
{
    $h = 0;
    $arr = explode(' ', $datetime);
    if (count($arr) > 1) {
        $h = intval($arr[1]);
    }

    $hours = [
        [21, 29],
        [6, 10],
        [11, 15],
        [16, 20],
    ];

    if ($h <= 5) {
        $h += 24;
    }

    for ($i = 0; $i < count($hours); $i++) {
        if ($h >= $hours[$i][0] && $h <= $hours[$i][1]) {
            $days = floor($idletime / 3600 / 24);
            $tag_idle_time = ($days * ($hours[$i][1] - $hours[$i][0])) * 3600 + ($h - $hours[$i][0]) * 3600 + $idletime % 3600;
            return [$i, $tag_idle_time];
            break;
        }
    }
    return [-1, 0];
}

class BikeIdleTimeMap
{
    static function idletime2rate($seconds)
    {
        if ($seconds > 0) {
            return intval(24 * 3600 / $seconds);
        }
        return 0;
    }


    function clear($city_id)
    {
        Db::table('tb_user_order_dist')->delete(['city_id'=>$city_id]);
    }


    function build($city_id, $start_date, $end_date)
    {
        $limit = 1000;
        for ($pos = 0; ; $pos += $limit) {
            $st = "city_id = ? and create_time >= ? and create_time < ? and bike_idle_time > 0";
            $beans = [
                $city_id,
                $start_date,
                $end_date,
            ];

            $result = hisql::db()->query($st, $beans);

            $rows = Db::table('tb_user_ride_order')->where($st,$beans)->field(['start_coordinate', 'bike_idle_time', 'create_time'])->limit($pos,1000)->select();
            if ($rows->isEmpty()) {
                break;
            }
            foreach ($rows as $row) {
                $coord = json_decode($row['start_coordinate'], true);
                if (empty($coord)) {
                    continue;
                }

                $bike_idle_time = intval($row['bike_idle_time']);
                if ($bike_idle_time == 0) {
                    $bike_idle_time = 3600 * 24;
                }
                $this->add($city_id, $coord, $row['create_time'], $bike_idle_time);
            }
        }
    }

    function add($city_id, $coord, $datetime, $idletime)
    {
        $this->upsert($city_id, $coord, 0, $idletime);
        list($tag, $tag_idle_time) = get_heat_tag_and_idletime($datetime, $idletime);
        $this->upsert($city_id, $coord, $tag, $tag_idle_time);
    }

    function upsert($city_id, $coord, $tag, $idletime)
    {
        $key = cord_gen_field($coord);

        $beans = [
            'city_id'=>$city_id,
            'coord'=>$key,
            'tag'=>$tag
        ];
        $aff = Db::table('tb_user_order_dist')->where($beans)->inc('order_count')->inc('idle_time_total',$idletime)->update();
        if ($aff == 0) {
            $data = [
                'city_id' => $city_id,
                'coord' => $key,
                'tag' => $tag,
                'order_count' => 1,
                'idle_time_total' => $idletime,
            ];
            Db::table('tb_user_order_dist')->insert($data);
        }
    }

    function point_order_rate($city_id, $coord, $radius, $tag = 0)
    {
        if ($radius > 200) {
            $radius = 200;
        }
        $coords = [];
        $lng_max = $coord[0] + $radius * 0.00001;
        $lng_min = $coord[0] - $radius * 0.00001;
        $lat_max = $coord[1] + $radius * 0.00001;
        $lat_min = $coord[1] - $radius * 0.00001;
        for ($lng = $lng_min; $lng <= $lng_max; $lng += AGG_LNG) {
            for ($lat = $lat_min; $lat <= $lat_max; $lat += AGG_LAT) {
                //$coords[] = hisql::db()->escapeString(cord_gen_field([s$lng, $lat]));
                $coords[] = cord_gen_field([$lng, $lat]);
            }
        }

        $selectlist = [
            'order_count' => 'int',
            'idle_time_total' => 'int',
        ];
        $sfs = common::array_keys($selectlist);
        $in = $coords;
        //$st = "select  sum(order_count) as ocnt, sum(idle_time_total) as ittotal from tb_user_order_dist where city_id = ? and  coord in ($in) and tag = ?";
        $beans = [
            'city_id'=>$city_id,
            'tag'=>$tag,
            'coord'=> ['in',$coords]
        ];
//
//        $rows = $result->fetchAll(Phalcon\Db::FETCH_ASSOC);
//        if (empty($rows)) {
//            return 3600 * 24 * 30;
//        }
        $ocnt = Db::table('tb_user_order_dist')->where($beans)->sum('order_count');
        $ittotal = Db::table('tb_user_order_dist')->where($beans)->sum('idle_time_total');
//        if ($ocnt == 0) {
//            return 3600 * 24 * 30;
//        }
//        $ittotal = intval($rows[0]['ittotal']);
        return self::idletime2rate($ittotal / $ocnt);
    }

    function get_heatmap($city_id, $tag)
    {
        //$st = "select coord, order_count, (idle_time_total/order_count) as cost from tb_user_order_dist where city_id = ? and tag = ? and order_count > 5";
        $beans = [
            'city_id'=>$city_id,
            'tag'=>$tag,
            'order_count'=>['>',5]];

        //$result = hisql::db()->query($st, $beans);
        $rows = Db::table('tb_user_order_dist')->where($beans)->field(['coord', 'order_count', '(idle_time_total/order_count) as cost'])->select();

        $order_rate_l = [];
        $order_count_l = [];
        foreach ($rows as $row) {
            $order_rate_l[] = [
                $row['coord'], self::idletime2rate(intval($row['cost']))
            ];
            $order_count_l[] = [
                $row['coord'], intval($row['order_count']),
            ];
        }
        return [$order_count_l, $order_rate_l];
    }
}

class BikeDistMapNew
{
    function add($city_id, $coord, $datetime)
    {
        $this->upsert($city_id, $coord, 0);
        $this->upsert($city_id, $coord, get_heat_tag($datetime));
    }

    function upsert($city_id, $coord, $tag)
    {
        $key = cord_gen_field($coord);

        $beans = [
            'city_id'=>$city_id,
            'coord'=>$key,
            'tag'=>$tag];
        $aff = Db::table('tb_bike_dist')->where($beans)->setInc('num',1);
        if ($aff == 0) {
            $data = [
                'city_id' => $city_id,
                'coord' => $key,
                'tag' => $tag,
                'num' => 1,
            ];
            Db::table('tb_bike_dist')->insert($data);
        }
    }

    function heatmap($city_id, $tag)
    {
        $beans = ['city_id'=>$city_id, 'tag'=>$tag];
        $rows=Db::table('tb_bike_dist')->where($beans)->where('num','>',5)->field(['coord','num'])->select();

        $l = [];
        foreach ($rows as $row) {
            $l[] = [
                $row['coord'], intval($row['num']),
            ];
        }
        return $l;
    }

}

class BikeCodeScanDistMapNew
{
    function add($city_id, $coord, $datetime)
    {
        $this->upsert($city_id, $coord, 0);
        $this->upsert($city_id, $coord, get_heat_tag($datetime));
    }

    function upsert($city_id, $coord, $tag)
    {
        $key = cord_gen_field($coord);

        //$st = "update tb_bike_code_scaned_dist set num=num+1 where city_id = ? and coord = ? and tag = ?";
        $beans = [
            'city_id'=>$city_id,
            'coord'=>$key,
            'tag'=>$tag];
        $aff = Db::table('tb_bike_code_scaned_dist')->where($beans)->setInc('num',1);
        if ($aff == 0) {
            $data = [
                'city_id' => $city_id,
                'coord' => $key,
                'tag' => $tag,
                'num' => 1,
            ];
            Db::table('tb_bike_code_scaned_dist')->insert($data);
        }
    }

    function heatmap($city_id, $tag)
    {
        $beans = ['city_id'=>$city_id, 'tag'=>$tag];
        $rows=Db::table('tb_bike_code_scaned_dist')->where($beans)->where('num','>',5)->field(['coord','num'])->select();

        $l = [];
        foreach ($rows as $row) {
            $l[] = [
                $row['coord'], intval($row['num']),
            ];
        }
        return $l;
    }
    function add_scanned_log($city_id,$info)
    {
        $data = [
            'city_id' => $city_id,
            'sn' => $info['sn'],
            'last_scaned_user_id' => $info['last_scaned_user_id'],
            'scaned_time' => date('Y-m-d H:i:s'),
        ];
        Db::table('tb_scaned_log')->insert($data);
    }
}

function city_build_heatmap($city_id)
{
    $start_date = hiredis::db()->get('HEATMAP_BUILD_START_TIME|' . $city_id);
    if (empty($start_date)) {
        $start_date = '2019-06-18 00:00:00';
    }

    $end_date = date('Y-m-d 23:59:59', strtotime($start_date));
    $lastday = date('Y-m-d 00:00:00', time() - 3600 * 24);
    if (strtotime($end_date) > strtotime($lastday)) {
        return;
    }

    $pos = 0;
    $limit = 1000;
    while (true) {

        $rows=Db::table('tb_user_ride_order')->where('city_id',$city_id)->where('create_time','>=',$start_date)->where('create_time','<',$end_date)->field(['create_time', 'end_time', 'start_coordinate', 'end_coordinate' ,'bike_idle_time'])->limit($pos,$limit)->select();

        foreach ($rows as $row) {
            $coord = json_decode($row['start_coordinate'], true);
            if (!empty($coord)) {
                $bike_idle_time = intval($row['bike_idle_time']);
                if ($bike_idle_time > 0) {
                    (new BikeIdleTimeMap())->add($city_id, $coord, $row['create_time'], $bike_idle_time);
                }
            }

            $coord = json_decode($row['end_coordinate'], true);
            if (!empty($coord)) {
                (new BikeDistMapNew())->add($city_id, $coord, $row['end_time']);
            }
        }

        $count = count($rows);
        $pos += $count;
        if (count($rows) < $limit) {
            break;
        }
    }

    Log::debug("heatmap scan tb_user_ride_order {$pos} record, start_time:{$start_date}, end_date:{$end_date}");

    $pos = 0;
    $limit = 1000;
    while (true) {
        $rows=Db::table('tb_bike_oper_record')->where('city_id',$city_id)->where('type',BIKE_OPER_TYPE_SCAN_BIKE_TDCODE)->where('create_time','>=',$start_date)->where('create_time','<',$end_date)->field(['coordinate', 'create_time'])->limit($pos,$limit)->select();


        foreach ($rows as $row) {
            $coord = json_decode($row['coordinate'], true);
            if (!empty($coord)) {
                (new BikeCodeScanDistMapNew())->add($city_id, $coord, $row['create_time']);
            }
        }
        $count = count($rows);
        $pos += $count;
        if (count($rows) < $limit) {
            break;
        }
    }

    Log::debug("heatmap scan tb_bike_oper_record {$pos} record, start_time:{$start_date}, end_date:{$end_date}");

    $pos = 0;
    $limit = 1000;
    while (true) {
        $rows=Db::table('tb_bike_repark_order')->where('city_id',$city_id)->where('create_time','>=',$start_date)->where('create_time','<',$end_date)->field(['create_time', 'end_coordinate'])->limit($pos,$limit)->select();


        foreach ($rows as $row) {
            $coord = json_decode($row['end_coordinate'], true);
            if (!empty($coord)) {
                (new BikeDistMapNew())->add($city_id, $coord, $row['create_time']);
            }
        }
        $count = count($rows);
        $pos += $count;
        if (count($rows) < $limit) {
            break;
        }
    }

    hiredis::db()->set('HEATMAP_BUILD_START_TIME|' . $city_id, date('Y-m-d H:i:s', strtotime($end_date) + 1));
    Log::debug("heatmap scan tb_bike_repark_order {$pos} record, start_time:{$start_date}, end_date:{$end_date}");


}